<template>
  <div class="max-w-4xl mx-auto p-6">
    <div class="flex items-start justify-between">
      <div>
        <h1 class="text-2xl font-semibold">AI免费在线抠图</h1>
        <p class="mt-2 text-gray-600">纯前端在浏览器中移除图片背景,由于需要加载一个小型的模型，首次加载可能较慢，请耐心等待。</p>
      </div>
      <NuxtLink to="/image-tools" class="text-blue-500">返回图片工具</NuxtLink>
    </div>

    <div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
      <!-- Controls -->
      <div class="space-y-4">
        <div>
          <div class="text-sm font-medium">上传图片</div>
          <input type="file" accept="image/*" @change="onFile" class="mt-2" />
        </div>

        <div class="border rounded p-4 space-y-3">
          <div class="text-sm">模型配置</div>
          <div class="flex gap-2 items-center">
            <label class="text-sm">设备</label>
            <select v-model="config.device" class="input">
              <option value="gpu">GPU (优先)</option>
              <option value="cpu">CPU</option>
            </select>
            <label class="text-sm">模型</label>
            <select v-model="config.model" class="input">
              <option value="small">small</option>
              <option value="medium">medium</option>
              <option value="large">large</option>
            </select>
          </div>

          <div>
            <label class="text-sm">输出类型</label>
            <select v-model="config.output.type" class="input mt-1">
              <option value="foreground">foreground</option>
              <option value="mask">mask</option>
              <option value="background">background</option>
            </select>
          </div>

          <div class="text-sm text-gray-600">模型状态： <span v-if="!ready">未加载</span><span v-else>已加载</span></div>
          <div class="text-sm text-gray-600">处理状态： <span v-if="processing">处理中…</span><span v-else>空闲</span></div>

          <div>
            <label class="text-sm">预览背景</label>
            <select v-model="bgChoice" class="input mt-1">
              <option value="checkerboard">马赛克（默认）</option>
              <option value="transparent">透明</option>
              <option value="white">纯白背景</option>
            </select>
          </div>

          <div class="flex gap-3">
            <button @click="initModel" :disabled="ready" class="btn btn-primary">加载模型</button>
            <button @click="downloadResult" :disabled="!resultUrl" class="btn">下载结果</button>
            <button @click="resetAll" class="btn">重置</button>
          </div>
        </div>
      </div>

      <!-- Preview -->
      <div>
        <div class="border rounded p-4">
          <div class="text-sm text-gray-600">预览</div>
          <div class="mt-3 bg-gray-50 p-3" style="min-height:240px">
            <div v-if="!originalUrl" class="text-gray-400">请上传图片开始抠图</div>

            <div v-else class="grid grid-cols-1 gap-3">
              <div>
                <div class="text-xs text-gray-500 mb-1">原图</div>
                <img :src="originalUrl" class="max-w-full" />
              </div>

              <div v-if="processing" class="text-sm text-gray-600">正在处理，请稍候...</div>

              <div v-if="resultUrl">
                <div class="text-xs text-gray-500 mb-1">抠图结果</div>
                <div class="inline-block" :style="previewWrapperStyle">
                  <img :src="resultUrl" class="max-w-full" />
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="mt-3 text-xs text-gray-500">注意：首次加载模型会下载约 20-30MB，随后会被缓存。</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch } from 'vue'
useHead({ title: '在线抠图 - 图片工具' })

const originalUrl = ref('')
const resultUrl = ref('')
const processing = ref(false)
const ready = ref(false)

// 预览背景选项：checkerboard | transparent | white
const bgChoice = ref('checkerboard')

// 存储原始（含透明通道）与处理后的 Blob
let rawResultBlob = null
let processedResultBlob = null

const previewWrapperStyle = computed(() => {
  switch (bgChoice.value) {
    case 'white':
      return 'background: white; padding:8px'
    case 'transparent':
      return 'background: transparent; padding:8px'
    case 'checkerboard':
    default:
      return 'background: repeating-conic-gradient(#ddd 0% 25%, white 0% 50%) 50% / 20px 20px; padding:8px'
  }
})

const config = reactive({
  device: 'gpu',
  model: 'medium',
  output: {
    format: 'image/png',
    quality: 1.0,
    type: 'foreground'
  }
})

let lib = null

async function initModel() {
  if (ready.value) return
  try {
    processing.value = true
    // 尝试以包名动态导入（如果你已通过 npm 安装）
    try {
      lib = await import('@imgly/background-removal')
    } catch (err) {
      // 如果未安装 npm 包，提示用户安装。不能保证 CDN ESM 接入在所有环境下都可用。
      console.error('import @imgly/background-removal failed', err)
      throw new Error('未检测到本地依赖，请运行 `npm install @imgly/background-removal` 后重试')
    }

    const cfg = { ...config }
    await lib.preload(cfg)
    ready.value = true
  } catch (e) {
    // 显示错误信息
    alert(e.message || String(e))
  } finally {
    processing.value = false
  }
}

async function onFile(e) {
  const f = e.target.files && e.target.files[0]
  if (!f) return
  if (originalUrl.value) {
    try { URL.revokeObjectURL(originalUrl.value) } catch (e) {}
  }
  originalUrl.value = URL.createObjectURL(f)
  resultUrl.value = ''
  await doRemoveBackground(f)
}

async function doRemoveBackground(file) {
  processing.value = true
  try {
    if (!lib) {
      await initModel()
      if (!lib) throw new Error('模型加载失败')
    }

    const cfg = { ...config }
    // 调用核心 API
    const blob = await lib.removeBackground(file, cfg)

    // 清理上一次的 raw/processed
    if (rawResultBlob && rawResultBlob !== blob) rawResultBlob = null
    rawResultBlob = blob

    // 根据当前背景选择决定是否合成白底
    if (bgChoice.value === 'white') {
      processedResultBlob = await applyWhiteBackground(blob)
    } else {
      processedResultBlob = blob
    }

    // 更新预览 URL（撤销旧的 URL）
    if (resultUrl.value) URL.revokeObjectURL(resultUrl.value)
    resultUrl.value = URL.createObjectURL(processedResultBlob)
  } catch (err) {
    console.error(err)
    alert('抠图失败: ' + (err.message || err))
  } finally {
    processing.value = false
  }
}

// 当用户切换预览背景时，如果已经有 rawResultBlob，则重新生成 processedResultBlob
watch(bgChoice, async (v, oldV) => {
  if (!rawResultBlob) return
  processing.value = true
  try {
    if (v === 'white') {
      processedResultBlob = await applyWhiteBackground(rawResultBlob)
    } else {
      // 恢复为原始包含透明通道的结果
      processedResultBlob = rawResultBlob
    }

    if (resultUrl.value) URL.revokeObjectURL(resultUrl.value)
    resultUrl.value = URL.createObjectURL(processedResultBlob)
  } catch (e) {
    console.error('重新应用背景失败', e)
  } finally {
    processing.value = false
  }
})

/**
 * 将含透明通道的图片合成为白底图片并返回新的 Blob
 */
function applyWhiteBackground(srcBlob) {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.onload = () => {
      const w = img.naturalWidth || img.width
      const h = img.naturalHeight || img.height
      const canvas = document.createElement('canvas')
      canvas.width = w
      canvas.height = h
      const ctx = canvas.getContext('2d')
      // 填充白色背景
      ctx.fillStyle = '#ffffff'
      ctx.fillRect(0, 0, w, h)
      // 绘制原图（含 alpha）
      ctx.drawImage(img, 0, 0, w, h)
      canvas.toBlob((b) => {
        if (!b) return reject(new Error('生成白底 Blob 失败'))
        resolve(b)
      }, 'image/png')
    }
    img.onerror = (e) => reject(e)
    const url = URL.createObjectURL(srcBlob)
    img.src = url
    // 载入后撤销临时 URL
    img.addEventListener('load', () => URL.revokeObjectURL(url), { once: true })
  })
}

function downloadResult() {
  if (!resultUrl.value) return
  const a = document.createElement('a')
  a.href = resultUrl.value
  // 如果用户选择白底，我们依然导出 PNG；否则导出含透明通道的 PNG
  a.download = 'remove-bg.png'
  document.body.appendChild(a)
  a.click()
  a.remove()
}

function resetAll() {
  if (originalUrl.value) {
    try { URL.revokeObjectURL(originalUrl.value) } catch (e) {}
  }
  if (resultUrl.value) {
    try { URL.revokeObjectURL(resultUrl.value) } catch (e) {}
  }
  originalUrl.value = ''
  resultUrl.value = ''
  processing.value = false
  rawResultBlob = null
  processedResultBlob = null
}
</script>

<style scoped>
.input {
  border: 1px solid #e5e7eb;
  border-radius: 0.375rem;
  padding: 0.25rem 0.5rem;
}
.btn {
  border: 1px solid #e5e7eb;
  border-radius: 0.375rem;
  padding: 0.5rem 0.75rem;
  background: #fff;
}
.btn-primary {
  background: #3b82f6;
  color: #fff;
  border-color: #3b82f6;
}
</style>
